package com.liveinstars.common.sort;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 提取双层排序抽象类
 * Created by guoyanjiang on 2019-01-28.
 */
public abstract class AbstractMultiLevelSortVO<T extends BaseCompareBean> {

    Logger logger = LoggerFactory.getLogger(getClass());

    public abstract List<T> provideSortList();

    public abstract void updateSortList(List<T> list);

    public List<T> doOrderOrPaging(String orderField, String orderType) {
        return doOrderOrPaging(new DefaultBasePageReq(orderField, orderType));
    }

    public List<T> doOrderOrPaging(Integer page, Integer size, String orderField, String orderType) {
        return doOrderOrPaging(new DefaultBasePageReq(page, size, orderField, orderType));
    }

    //todo 排序代码需要抽出公共方法 ps 不但需要抽出公共方法，排序的Bean框架最好能抽离，可以做到需要排序的VO只要实现基类中的抽象方法即可
    public List<T> doOrderOrPaging(BasePageReq req) {
        String orderField = req.getOrderfield();
        String orderType = req.getOrdertype();
        //todo 业务代码写完后在尝试
        Stream<T> tickerStream = provideSortList().stream();

        if (req.needOrder()) {
            Comparator<T> comparator = (o1, o2) -> doCompare(orderField, o1, o2);
            if (! "asc".equals(orderType)) {
                comparator = comparator.reversed();
            }
            tickerStream = tickerStream.sorted(comparator);
        }

        if (req.needPaging()) {
            Integer pageSize = req.checkAndGetPageSizeForWeb();
            Integer pageNum = req.checkAndGetPageForWeb();
            tickerStream = tickerStream.skip(pageSize * (pageNum - 1)).limit(pageSize);
        }
        List<T> list = tickerStream.collect(Collectors.toList());
        updateSortList(list);
        return list;
    }

    public int doCompare(String orderField, T o1, T o2) {
        try {
            if (orderField.contains(".")) {
                //说明要用第二层数据排序
                String[] fields = orderField.split("\\.");
                Comparable v1 = o1.tryBestToFindFieldValue(fields[0], BaseCompareBean.class).tryBestToFindCompareValue(fields[1]);
                Comparable v2 = o2.tryBestToFindFieldValue(fields[0], BaseCompareBean.class).tryBestToFindCompareValue(fields[1]);
                return v1.compareTo(v2);
            } else {
                //直接取PairInfo类里的字段
                return o1.tryBestToFindCompareValue(orderField).compareTo(o2.tryBestToFindCompareValue(orderField));
            }
        } catch (Exception e) {
            logger.error("获取指定比较字段失败，放弃比较。 orderField {}", orderField);
            return 0;
        }
    }

    //先留着
//    private Comparator<Object> getSortComparator(String orderfield, String ordertype, String needMultiConvertCnyField) {
//        return (a, b) -> {
//            int num = 0;
//            try {
//                String[] fields = orderfield.split("\\.");
//                Double aDouble = getaFieldValue((PairInfo) a, fields, needMultiConvertCnyField);
//                Double bDouble = getaFieldValue((PairInfo) b, fields, needMultiConvertCnyField);
//                if ("asc".equals(ordertype)) {
//                    num = aDouble.compareTo(bDouble);
//                } else {
//                    num = bDouble.compareTo(aDouble);
//                }
//            } catch (Exception ex) {
//                logger.error("获取比较器异常", ex);
//            } finally {
//                return num;
//            }
//        };
//    }

    /*
    orderfield 有这几种情况：fee/ticker.last(需要转cny)/ticker.sell(不需要转cny)
    但是：无论转不转cny，都对排序没影响吧？是不是可以直接排。
    先留着 有机会讨论
     */
//    private Double getaFieldValue(PairInfo a, String[] fields, String needMultiConvertCnyField) {
//        double convert_cny = 1d;
//        if (fields.length == 1) {
//            if (needMultiConvertCnyField.contains(fields[0])) {
//                convert_cny = a.getConvertCny();
//            }
//            Double doubleValue = a.tryBestToFindFieldValue(fields[0], Double.class);
//            return doubleValue * convert_cny;
//        } else if (fields.length == 2) {
//            if (needMultiConvertCnyField.contains(fields[1])) {
//                convert_cny = a.getConvertCny();
//            } else if (needMultiConvertCnyField.contains(".*")) {
//                convert_cny = a.getConvertCny();
//            }
//            Double doubleValue = a.getTicker().tryBestToFindFieldValue(fields[1], Double.class);
//            return doubleValue * convert_cny;
//        }
//        return 0d;
//    }

}
